<?php
namespace base\pay;
use lib\wechat\Wechat;
use lib\wechat\WechatAppPay;
use think\facade\Cache;

error_reporting(E_ERROR | E_WARNING | E_PARSE);

//---------------------------------
//---------微信api----------------
//---------------------------------
class WxApi {

	private $mch_id;
	private $notify_url;
	private $refund_url;
	private $trade_type;
	private $key;
	private $sub_mch_id;
	private $sub_appid;
	private $appid;
	private $cacert;
	private $config;
	
	//初始配置
	public function __construct($mode="applets")//   h5，applets
	{
	    //config("wechat.web");
        $this->config = $config = env('system_base_config_wx_web'); 
        if(!$config){
           throw new \think\Exception( '请先配置微信应用信息' );
        }
		$this->appid = $mode == "applets" ? $config['applets_appid'] : $config['appid'];
		$this->mch_id = $config['mch_id'];
		$this->notify_url = env('APP_HOST').$config['notify_url'];
		$this->refund_url = env('APP_HOST').$config['refund_url'];
		$this->key = $config['key'];
		$this->trade_type = $config['trade_type'];
		$this->trade_type = $config['trade_type'];
		if($config['sub_mch_id'])  $this->sub_mch_id = $config['sub_mch_id'];
		if($config['sub_appid'])  $this->sub_appid = $config['sub_appid'];
    	$this->cacert = root_path().'cacert';
	}
	
	//当前付款对象
	public function pay($refund=false)
    {
		return new wechatAppPay( 
			$this->appid,
			$this->mch_id, 
			($refund ? $this->refund_url : $this->notify_url), 
			$this->key,
			$this->cacert,
			$this->sub_mch_id,
			$this->sub_appid
		);
    }
	
	/**
	* 获取jsDk签名
	*/
    public static function getSignPackage()
    {
    	$weObj = new Wechat( (new self)->config  );
		$auth = $weObj->checkAuth();
		if($auth){
			return $weObj->getJsSign(input('url') ?: env('APP_HOST'));//获取签名
		}else{
			throw new \think\Exception( $weObj->errMsg );
		}
    }
	
	/** 微信支付-下单
     * @param $orderNo
     * @param array $opt
     * @return bool
     */
    public  function createOrder($order_no,$total_fee,$openid='',$profit_sharing="N",$body='')
    {
		//参数
		$params['body'] = $body ?: '商品付款'; //商品描述
		$params['out_trade_no'] = $order_no; //自定义的订单号
		$params['total_fee'] = (float)($total_fee * 100); //订单金额 只能为整数 单位为分
		//交易类型 JSAPI | NATIVE | APP | WAP | MWEB
		$params['trade_type'] = $trade_type =  (new self)->trade_type; 
		if($trade_type =='JSAPI' ){
			$params['openid'] = $openid ?: request()->userInfo['openid']; 
		}
		
		//是否分账
		if($profit_sharing == 'Y'){
			$params['profit_sharing'] = $profit_sharing; 
		}

		$wechatAppPay = $this->pay();
		$result = $wechatAppPay->unifiedOrder( $params );
		if($result['return_code'] == "SUCCESS" && $result['result_code']!='FAIL'){
			if($result['mweb_url']){
				return env('APP_HOST').'/system/payment/wxPay.html?url='.
				urlencode($result['mweb_url']).'&redirect_url='.urlencode(request()->host());
			}else{
				$payParams=  $wechatAppPay->getAppPayParams( $result['prepay_id'] );
				$payParams['timeStamp'] = ''.$payParams['timeStamp'];
				return $payParams;
			}
		}else{
			throw new \think\Exception( $result['err_code_des'] ?? $result['return_msg'] );
		}
       
    }
	
	/** 根据订单号查询订单付款状态
     * @param $orderNo
     * @param array $opt
     * @return bool
     */
    public  function orderQuery($order_no,$is=false)
    {
		$result = $this->pay()->orderQuery( $order_no );
		if($is) return $result;
		if($result['return_code']=="SUCCESS" && $result['trade_state_desc']=="支付成功" ){
			return true;
		}else{
			return false;
		}
    }
    
    /** 发起分账
     * @param $orderNo
     * @param array $opt
     * @return bool
     */
    public  function profitSharing($orderNo,$transaction_id,$openid,$price,$name='')
    {
		try {
			$receivers = [[
				"type"=>"PERSONAL_OPENID",
	      		"account"=>$openid,
	      		"amount"=>(float)($price * 100),
	      		"description"=>"用户下单到账",
	      		//"name"=> '',
		    ]];
			$res = $this->pay()->profitSharing($orderNo,$transaction_id,$receivers);
			if ($res['result_code'] == 'FAIL' || isset($res['err_code']) ) {
				throw new \think\Exception( $res['err_msg'] );
			}
			return true;
        } catch (\Exception $e) {
        	throw new \think\Exception( $e->getMessage() );
        }
    }
    
    /** 完结分账
    * @param $orderNo
    * @param array $opt
    * @return bool
    */
    public  function profitsharingfinish($orderNo,$transaction_id)
    {
		try {
			$res = $this->pay()->profitsharingfinish($out_order_no,$transaction_id);
			if ($res['result_code'] == 'FAIL' || isset($res['err_code']) ) {
				throw new \think\Exception( $res['err_msg'] );
			}
			return true;
        } catch (\Exception $e) {
        	throw new \think\Exception( $e->getMessage() );
        }
    }
    
	
	/** 根据订单号关闭订单
     * @param $orderNo
     * @param array $opt
     * @return bool
     */
    public  function closeOrder($order_no)
    {
		$result = $this->pay()->closeOrder( $order_no);
		if($result['result_code'] == 'FAIL'){
			return false;
		}else{
			return true;
		}
    }

	/** 根据订单号退款
     * @param $orderNo
     * @param array $opt
     * @return bool
     */
    public  function payOrderRefund($orderNo,$price)
    {
		$params['out_trade_no'] = $orderNo; //自定义的订单号
		$params['total_fee'] = (float)($price * 100); //订单金额 只能为整数 单位为分
		$params['trade_type'] = (new self)->trade_type;  //交易类型 JSAPI | NATIVE | APP | WAP
		try {
			$res = $this->pay(true)->refund( $params );
			if ($res['result_code'] == 'FAIL' || isset($res['err_code']) ) {
				throw new \think\Exception( $res['err_msg'] );
			}
			return true;
        } catch (\Exception $e) {
        	throw new \think\Exception( $e->getMessage() );
        }
    }
	
	/** 微信提现用户微信
     * @param $orderNo
     * @param array $opt
     * @return bool
     */
    public  function withdrawal($openid,$orderNo,$name,$price,$desc)
    {
		$params['out_trade_no'] = $orderNo; //自定义的订单号
		$params['user_name'] = $name; //用户名称
		$params['check_name'] = 'NO_CHECK'; //FORCE_CHECK
		$params['total_fee'] = (float)($price * 100); //订单金额 只能为整数 单位为分
		$params['desc'] = $desc ?: '---';  //提现描述
		$params['openid'] =$openid;  //用户openid
		try {
			$res = $this->pay()->payWx( $params );
			if ($res['result_code'] == 'FAIL' || isset($res['err_code']) ) {
				throw new \think\Exception( $res['err_msg'] );
			}
			return true;
        } catch (\Exception $e) {
        	throw new \think\Exception( $e->getMessage() );
        }
    }
	
	/** 获取公钥
     * @return bool
     */
	public  function getPubKey(){
		$res = $this->pay()->get_pub_key();
		if ( !is_string($res)  && ($res['result_code'] == 'FAIL' || isset($res['err_code'])) ) {
			throw new \think\Exception( $res['err_msg'] );
		}
		return true;
	}
	
	/** 微信提现到银行
     * @param $orderNo
     * @param array $opt
     * @return bool
     */
    public  function withdrawalBank($orderNo,$userName,$price,$bankCode,$bankName,$desc)
    {
		$params['out_trade_no'] = $orderNo; //自定义的订单号
		$params['user_name'] = $name; //用户名称
		$params['check_name'] = 'NO_CHECK'; //FORCE_CHECK
		$params['total_fee'] = (int)($price * 100); //订单金额 只能为整数 单位为分
		$params['desc'] = $desc ?: '---';  //提现描述
		$params['bank_code'] = $bankCode;  //银行编码
		$params['bank_name'] =$bankName;  //银行名称
		try {
			$res = $this->pay(true)->payBank( $params );
			if ($res['result_code'] == 'FAIL' || isset($res['err_code']) ) {
				throw new \think\Exception( $res['err_msg'] );
			}
			return true;
        } catch (\Exception $e) {
        	throw new \think\Exception( $e->getMessage() );
        }
    }
	
	
	/**
	* 获取小程序二维码
	* $url  pages/index/index  小程序路径
	* $scene 参数
	* $width 二维码宽度  是否需要透明底色
	* $is_hyaline false  是否需要透明底色
	*/
    public function getAppQRCode(String $url="",String $scene='',$width=150,$is_hyaline=false)
    {
    	$weObj = new Wechat([
            "appid"=> $this->config['applets_appid'],
            "appsecret"=> $this->config['applets_appsecret']
        ]);
		$res = $weObj->getAppQRCode($url ?: 'pages/index/index',$scene,$width,$is_hyaline);//获取签名
		if(!$res){
			throw new \think\Exception($weObj->errMsg);
		}
		return $res;
    }
}


